/**
 * 
 */
package communication;

import infrastructure.CommunicationCustomException;
import infrastructure.LoggingManager;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.net.UnknownHostException;

import org.apache.log4j.Logger;

import ui.Application;

/**
 * @author Danielondon
 *
 */
public class Communication implements ICommunication{

	Socket myClientConnection;
	InputStream myInputStream;
	OutputStream myOutputStream;
	Logger logger;
	
	public Communication()
	{
		logger = LoggingManager.CreateLogger(Communication.class);		
	}
	
	@Override
	public boolean Connect(String ipaddress, String port) throws Exception, CommunicationCustomException {
		logger.info("Connecting");
		// Establish Connection
		int _port;
		try {
			_port = Integer.parseInt(port);
		}
		catch (NumberFormatException ex){
			throw new CommunicationCustomException("Error. Port is not in a correct format.");
		}
		
		if (this.myClientConnection == null || this.myClientConnection.isClosed()){			
			this.myClientConnection = new Socket(ipaddress, _port);			
			this.myInputStream = this.myClientConnection.getInputStream();
			this.myOutputStream =  this.myClientConnection.getOutputStream();	
		}
		else{
			throw new CommunicationCustomException(String.format("Connection is already established with server %s", 
					this.myClientConnection.getInetAddress().getHostAddress()));
		}
		
		return this.myClientConnection.isConnected();
	}
	
	/**
	 * Closes the socket and the output and input stream.
	 * @throws CommunicationCustomException 
	 */
	@Override
	public void Disconnect() throws IOException, CommunicationCustomException {
		logger.info("Disconnecting");
		if(this.myClientConnection == null)
			throw new CommunicationCustomException("Communication has not been created yet.");
		
		if (this.myClientConnection.isClosed())
			throw new CommunicationCustomException("Communication is already closed.");
		
		this.myOutputStream.close();
		this.myInputStream.close();
		this.myClientConnection.close();
	}

	/**
	 * Sends a string message 
	 */
	@Override
	public void SendMessage(String message) throws Exception {
		// Sends Message
		if(this.myClientConnection != null && !this.myClientConnection.isClosed())
		{
			this.send(message.getBytes());
		}
		else
		{
			throw new CommunicationCustomException("Error. There is no connection available or connection has been lost.");
		}
	}
	
	/**
	 * Receives a string message.
	 */
	public String ReceiveMessage() throws IOException {	
		return new String(this.receive());
	}

	/**
	 * Sends a set of bytes through a stream.
	 * @return
	 * @throws IOException
	 */
	private byte[] receive() throws IOException{
		logger.info("Reading bytes");
		// Read bytes
		int bytesAvailable = this.myInputStream.available();
		if (bytesAvailable == 0)
		{
			bytesAvailable = 100;
		}
		
		byte[] message = new byte[bytesAvailable];
		int result = this.myInputStream.read(message);
		result++;
		return message;
	}
	
	/**
	 * Reads the bytes from the input stream.
	 * @param message
	 * @throws IOException
	 */
	private void send(byte[] message) throws Exception{
		// Reads bytes
		logger.info("Writting bytes");
		this.myOutputStream.write(message);
		this.myOutputStream.flush();
	}
	
}
